#!/usr/bin/python
# -*- coding: utf-8 -*-
# @author  : ganuoxun
# @description : 贴源层数据操作

import pymongo
import traceback

from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase, AsyncIOMotorCollection, \
    AsyncIOMotorGridFSBucket
from apps.models.ResponseModel import success, error
from apps.utils.ObjectUtils import dict_is_empty
import json


class MongoUtil:
    client: AsyncIOMotorClient
    db: AsyncIOMotorDatabase
    fs: AsyncIOMotorGridFSBucket
    cclp_ods: AsyncIOMotorCollection
    cclp_dwd: AsyncIOMotorCollection
    # cclp_dws_person: AsyncIOMotorCollection
    # cclp_dws_place: AsyncIOMotorCollection
    # cclp_dws_date: AsyncIOMotorCollection
    # cclp_dws_work: AsyncIOMotorCollection
    # cclp_dws_chapter: AsyncIOMotorCollection

    def init(self, mongo_uri):
        self.client = AsyncIOMotorClient(mongo_uri)
        self.db = self.client.cclp_db
        self.fs = AsyncIOMotorGridFSBucket(self.db, 'cclp_ods_result')
        self.cclp_ods = self.db.get_collection("cclp_ods")
        self.cclp_dwd = self.db.get_collection("cclp_dwd")
        # self.cclp_dws_person = self.db.get_collection("cclp_dws_person")
        # self.cclp_dws_place = self.db.get_collection("cclp_dws_place")
        # self.cclp_dws_date = self.db.get_collection("cclp_dws_date")
        # self.cclp_dws_work = self.db.get_collection("cclp_dws_work")
        # self.cclp_dws_chapter = self.db.get_collection("cclp_dws_chapter")


mongo = MongoUtil()


async def get_ods(_filter: dict, projection: dict, sort_by: dict,
                  skip: int, limit: int) -> list:
    """
    根据条件查询贴源层的MongoDB

    Args:
        _filter: 查询条件
        projection: 指定返回的字段
        sort_by: 排序
        skip: 跳过的数据量
        limit: 返回的数量

    Returns:
    """
    # if dict_is_empty(_filter):
    #     _filter = {}
    # if dict_is_empty(projection):
    #     projection = None
    #
    # cursor = cclp_ods.find(filter=_filter, projection=projection).skip(skip).limit(limit)
    #
    # if not dict_is_empty(sort_by):
    #     cursor = cursor.sort(sort_by)

    if not dict_is_empty(projection) and not dict_is_empty(sort_by):
        cursor = mongo.cclp_ods.find(_filter, projection).sort(sort_by).skip(skip).limit(limit)
    elif dict_is_empty(projection) and not dict_is_empty(sort_by):
        cursor = mongo.cclp_ods.find(_filter).sort(sort_by).skip(skip).limit(limit)
    elif not dict_is_empty(projection) and dict_is_empty(sort_by):
        cursor = mongo.cclp_ods.find(_filter, projection).skip(skip).limit(limit)
    else:
        cursor = mongo.cclp_ods.find(_filter).skip(skip).limit(limit)

    results = []
    async for document in cursor:
        results.append(document)
    return results


async def save_ods(_filter: dict, replacement: dict) -> dict:
    """
    将数据更新到贴源层的mongodb，强制upsert为True

    Args:
        _filter: 需要更新的条件，格式为：{'_id': _id}
        replacement: 需要更新的字段内容

    Returns:
        ResponseModel: 保存结果，成功code为200，失败code为500
    """
    try:
        await mongo.cclp_ods.replace_one(filter=_filter,
                                         replacement=replacement,
                                         upsert=True)
        return success(None, "success")
    except Exception as e:
        traceback.print_exc()
        return error(500, repr(e))


async def bulk_write_ods(docs: list) -> dict:
    """
    批量的将数据更新到贴源层的mongodb，强制upsert为True
    Args:
        docs:

    Returns:
        ResponseModel: 保存结果，成功code为200，失败code为500
    """
    requests = []
    try:
        for doc in docs:
            requests.append(pymongo.ReplaceOne({"_id": doc["lngid"]},
                                               replacement=doc,
                                               upsert=True))
        await mongo.cclp_ods.bulk_write(requests)
        return success(None, "success")
    except Exception as e:
        traceback.print_exc()
        return error(500, repr(e))


async def update_ods(_filter: dict, update: dict) -> dict:
    """
    更新贴源层MongoDB指定_id的字段，强制upsert为False

    Args:
        _filter: 需要更新的条件，格式为：{'_id': _id}
        update: 需要更新的字段内容

    Returns:
        ResponseModel: 保存结果，成功code为200，失败code为500
    """
    try:
        await mongo.cclp_ods.update_one(filter=_filter,
                                        update={'$set': update},
                                        upsert=False)
        return success(None, "success")
    except Exception as e:
        traceback.print_exc()
        return error(500, repr(e))


async def save_ods_result(file_id: str, file_name: str, result: str, metadata: dict) -> dict:
    """
    将整个文件json结构化的结果存入gridfs中
    Args:
        file_id: 指定的文件id
        file_name: 指定的文件名
        result: 文件json结构化的文本字符串
        metadata: 元数据

    Returns:

    """
    try:
        try:
            await mongo.fs.delete(file_id=file_id)
        except Exception as e:
            print(repr(e))
            print(f"警告: {file_id}文件不存在")
        await mongo.fs.upload_from_stream_with_id(file_id=file_id,
                                                  filename=file_name,
                                                  source=result.encode('utf-8'),
                                                  metadata=metadata)
        return success(None, "success")
    except Exception as e:
        print(repr(e))
        traceback.print_exc()
        return error(500, traceback.format_exc())


async def get_ods_result_by_id(_id: str) -> dict:
    """
    查询贴源层解析结果的指定_id的数据
    Args:
        _id: 指定的file_id
    Returns:
    """
    try:
        result = await mongo.fs.open_download_stream(file_id=_id)
        result_bytes = await result.read()
        return success(json.loads(result_bytes.decode('utf-8')), "success")
    except Exception as e:
        traceback.print_exc()
        return error(500, repr(e))


async def get_ods_result(_filter: dict, sort_by: dict, skip: int,
                         limit: int) -> list:
    """
    根据条件查询贴源层解析结果的MongoDB

    Args:
        _filter: 查询条件
        sort_by: 排序
        skip: 跳过的数据量
        limit: 返回的数量

    Returns:
    """
    if dict_is_empty(_filter):
        _filter = {}

    cursor = mongo.fs.find(_filter)
    if not dict_is_empty(sort_by):
        cursor = cursor.sort(sort_by)
    cursor = cursor.skip(skip).limit(limit)

    results = []
    async for grid_out in cursor:
        results.append(json.loads(grid_out.read()))
    return results


async def save_dwd(_filter: dict, replacement: dict) -> dict:
    """
    将数据更新到明细层的mongodb，强制upsert为True

    Args:
        _filter: 需要更新的条件，格式为：{'_id': _id}
        replacement: 需要更新的字段内容

    Returns:
        ResponseModel: 保存结果，成功code为200，失败code为500
    """
    try:
        await mongo.cclp_dwd.replace_one(filter=_filter,
                                         replacement=replacement,
                                         upsert=True)
        return success(None, "success")
    except Exception as e:
        traceback.print_exc()
        return error(500, repr(e))


async def get_dwd(_filter: dict, projection: dict, sort_by: dict,
                  skip: int, limit: int) -> list:
    """
    根据条件查询明细层的mongodb

    Args:
        _filter: 查询条件
        projection: 指定返回的字段
        sort_by: 排序
        skip: 跳过的数据量
        limit: 返回的数量

    Returns:
    """
    if not dict_is_empty(projection) and not dict_is_empty(sort_by):
        cursor = mongo.cclp_dwd.find(_filter, projection).sort(sort_by).skip(skip).limit(limit)
    elif dict_is_empty(projection) and not dict_is_empty(sort_by):
        cursor = mongo.cclp_dwd.find(_filter).sort(sort_by).skip(skip).limit(limit)
    elif not dict_is_empty(projection) and dict_is_empty(sort_by):
        cursor = mongo.cclp_dwd.find(_filter, projection).skip(skip).limit(limit)
    else:
        cursor = mongo.cclp_dwd.find(_filter).skip(skip).limit(limit)
    results = []
    async for document in cursor:
        results.append(document)
    return results


async def save_dwm(col_name: str, _filter: dict, replacement: dict) -> dict:
    """
    将数据更新到中间层的mongodb，强制upsert为True

    Args:
        col_name: 中间层的集合名称
        _filter: 需要更新的条件，格式为：{'_id': _id}
        replacement: 需要更新的字段内容

    Returns:
        ResponseModel: 保存结果，成功code为200，失败code为500
    """
    try:
        if not col_name.startswith("cclp_dwm"):
            return error(501, "集合名称不属于数据中间层!")

        collection = mongo.db.get_collection(col_name)
        await collection.replace_one(filter=_filter,
                                     replacement=replacement,
                                     upsert=True)
        return success(None, "success")
    except Exception as e:
        print(e)
        return error(500, repr(e))


async def bulk_write_dwm(col_name: str, docs: list) -> dict:
    """
    批量的将数据更新到中间层的mongodb，强制upsert为True
    Args:
        col_name: 中间层的集合名称
        docs: 需要更新文档

    Returns:
        ResponseModel: 保存结果，成功code为200，失败code为500
    """
    requests = []
    try:
        if not col_name.startswith("cclp_dwm"):
            return error(501, "集合名称不属于数据中间层!")
        collection = mongo.db.get_collection(col_name)

        for doc in docs:
            requests.append(pymongo.ReplaceOne({"_id": doc["_id"]},
                                               replacement=doc,
                                               upsert=True))
        await collection.bulk_write(requests)
        return success(None, "success")
    except Exception as e:
        print(e)
        return error(500, repr(e))


async def get_dwm(col_name: str, _filter: dict, projection: dict,
                  sort_by: dict, skip: int, limit: int) -> list:
    """
    根据条件查询中间层的mongodb

    Args:
        col_name: 中间层的集合名称
        _filter: 查询条件
        projection: 指定返回的字段
        sort_by: 排序
        skip: 跳过的数据量
        limit: 返回的数量

    Returns:
    """
    if not col_name.startswith("cclp_dwm"):
        return error(501, "集合名称不属于数据中间层!")
    collection = mongo.db.get_collection(col_name)

    if not dict_is_empty(projection) and not dict_is_empty(sort_by):
        cursor = collection.find(_filter, projection).sort(sort_by).skip(skip).limit(limit)
    elif dict_is_empty(projection) and not dict_is_empty(sort_by):
        cursor = collection.find(_filter).sort(sort_by).skip(skip).limit(limit)
    elif not dict_is_empty(projection) and dict_is_empty(sort_by):
        cursor = collection.find(_filter, projection).skip(skip).limit(limit)
    else:
        cursor = collection.find(_filter).skip(skip).limit(limit)
    results = []
    async for document in cursor:
        results.append(document)
    return results


async def get_dwm_by_id(col_name: str, _id: str) -> dict:
    """
    查询中间层指定集合名称指定_id的数据
    Args:
        col_name: 集合名称
        _id: 指定的主键ID
    Returns:
    """
    try:
        if not col_name.startswith("cclp_dwm"):
            return error(501, "集合名称不属于数据中间层!")
        collection = mongo.db.get_collection(col_name)
        result = await collection.find_one({"_id": _id})
        return success(result, "success")
    except Exception as e:
        print(e)
        return error(500, repr(e))
